#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import os
import string

from oriolus.pith.packets.hashbuilder import HashBuilder

class HashFileWriterError(Exception):
    def __init__(self, message):
        Exception.__init__(self, message)

class HashFileWriter:
    def __init__(self, name):
        self.__name = name
        self.__template = string.Template("$data\t$file_name\n") #pattern for string representation. Can be changed and sorted by file_names

    def write_string(self, fd, file_, hash_data):
        str = self.__template.substitute(data=hash_data, file_name=file_)
        fd.write(str)
        fd.flush()

    def write_strings(self, dict):
        fd = None
        try:
            fd = file(self.__name, "w")
            list = dict.keys()
            list.sort()
            for file_ in list:
                self.write_string(fd, file_, dict[file_])
        except Exception, error:
            raise HashFileWriterError(error.message)
        
        finally:                
            if fd: fd.close()

class StrategyError(Exception):
    def __init__(self, message):
        Exception.__init__(self, message)
        
class Strategy:
    def get_file_hash(self, file_name):
        hash = HashBuilder("md5")
        
        fd = None
        try:
            fd = file(file_name, "rb")
            data = fd.read()            
        except Exception, error:
            raise StrategyError(error.message)
        finally:
            if fd: fd.close()
        
        return hash.get_hash(data)


class Visitor:
    def __init__(self, path):
        self.__path = path

    def list(self, action):
        #verify action is not None

        result = {}
        for root, dirs, files in os.walk(self.__path):
            for dir in dirs:
                if dir.startswith("."):
                    dirs.remove(dir)
                    
            for name in files:
                if not name.startswith("."):
                    str = os.path.normpath(os.path.join(self.__relpath(root, self.__path), name))
                    result[str.replace("\\", "/")] = action(os.path.join(root, name))

        return result
        
    def __relpath(self, path, reldir):
        #http://code.activestate.com/recipes/302594/
        #returns 'path' relative to 'reldir'."""
    
        # use normpath to ensure path separators are uniform
        path = os.path.normpath(path)
    
        # find length of reldir as prefix of path (or zero if it isn't)
        prelen = len(os.path.commonprefix((
            os.path.normcase(path),
            # add a separator to get correct prefix length
            # (normpath removes trailing separators)
            os.path.normcase(os.path.normpath(reldir)) + os.sep
            )))
        return path[prelen:]
